package cn.csc.module.order.controller.app;

import cn.csc.framework.common.pojo.CommonResult;
import cn.csc.framework.common.pojo.PageResult;
import cn.csc.framework.common.util.servlet.ServletUtils;
import cn.csc.module.order.controller.admin.order.vo.OrderPageReqVO;
import cn.csc.module.order.controller.app.dto.OrderAmtDTO;
import cn.csc.module.order.controller.app.dto.OrderCreateReqDTO;
import cn.csc.module.order.controller.app.dto.OrderDeliveryReqDTO;
import cn.csc.module.order.controller.app.dto.OrderToPayReqDTO;
import cn.csc.module.order.controller.app.vo.OrderRespVO;
import cn.csc.module.order.controller.app.vo.OrderShopRespVO;
import cn.csc.module.order.dal.dataobject.order.OrderDO;
import cn.csc.module.order.enums.*;
import cn.csc.module.order.mq.producer.hzh.OrderDeliverForHzhProducer;
import cn.csc.module.order.service.order.OrderService;
import cn.csc.module.pay.api.order.PayOrderApi;
import cn.csc.module.pay.api.order.dto.PayOrderCreateReqDTO;
import cn.csc.module.product.api.sku.SkuApi;
import cn.csc.module.product.api.spu.SpuApi;
import cn.csc.module.product.api.spu.dto.SpuDTO;
import cn.csc.module.shop.api.detail.ShopDetailApi;
import cn.csc.module.shop.api.detail.dto.ShopDetailRespDTO;
import cn.csc.module.shop.api.user.ShopUserApi;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.IdUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import static cn.csc.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.csc.framework.common.pojo.CommonResult.success;
import static cn.csc.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.csc.module.order.enums.ErrorCodeConstants.ORDER_SUBMIT_DUPLICATE;

/**
 * 订单信息
 */
@RestController("appOrderController")
@RequestMapping("/order")
@Tag(name = "app-订单信息")
@Slf4j
public class AppOrderController {

    @Autowired
    private OrderService orderService;
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SkuApi skuApi;
    @Autowired
    private SpuApi spuApi;
    @Autowired
    private ShopUserApi shopUserApi;

    @Autowired
    private ShopDetailApi shopDetailApi;

    @Autowired
    private PayOrderApi payOrderApi;
    @Value("${csc.pay.appId}")
    private BigInteger appId;

    @Autowired
    private OrderDeliverForHzhProducer orderDeliverForHzhProducer;


    /**
     * 生成订单（单个sku）
     *
     * @return
     */
    @PostMapping("/confirm")
    @Operation(summary = "结算，生成订单信息", description = "传入下单所需要的参数进行下单")
    public CommonResult<BigInteger> confirm(@Valid @RequestBody OrderCreateReqDTO reqDTO) {
        // 获取订单缓存
        Object orderCache = redisTemplate.opsForValue().get(OrderCacheNames.ORDER_CONFIRM_KEY + reqDTO + CacheNames.UNION_KEY + reqDTO.getAllCount());
        if (orderCache != null) {
            throw exception(ORDER_SUBMIT_DUPLICATE);
        }
        // 重算一遍订单金额
        OrderAmtDTO orderAmtDTO = recalculateAmountWhenFinishingCalculateShop(reqDTO.getSpuId(), reqDTO.getSkuId(), reqDTO.getAllCount());
        log.info("[OrderController][confirm][orderAmtDTO]{}",orderAmtDTO);
        //订单金额不能超过50000元
        if (orderAmtDTO.getTotal().compareTo(new BigDecimal(50000)) == 1) {
            return CommonResult.error(ErrorCodeConstants.ORDER_AMT_MAX_EXISTS);
        }
        log.info("[OrderController][confirm][getLoginUserId]{}",getLoginUserId());
        reqDTO.setTotal(orderAmtDTO.getTotal());
        reqDTO.setUserId(BigInteger.valueOf(getLoginUserId()));
        if(StringUtil.isEmpty(reqDTO.getNickName())) {
            reqDTO.setNickName("微信用户");
        }

        reqDTO.setPic(orderAmtDTO.getPic());
        reqDTO.setProductPrice(orderAmtDTO.getProductPrice());
        if (reqDTO.getDvyType() == null) {
            // 无需快递
            reqDTO.setDvyType(3);
        }
        // 缓存，防止重复提交
        redisTemplate.opsForValue().set(OrderCacheNames.ORDER_CONFIRM_KEY + reqDTO + CacheNames.UNION_KEY + reqDTO.getAllCount(), getLoginUserId(), 30L, TimeUnit.MINUTES);

        BigInteger orderId = orderService.saveOrder(reqDTO);
        return success(orderId);
    }

    /**
     * 这里有提交订单的代码（单个sku）
     * 提交商品订单
     */
    @PostMapping("/submit")
    @Operation(summary = "提交订单，返回支付流水号", description = "根据传入的参数判断是否为购物车提交订单，同时对购物车进行删除，用户开始进行支付")
    public CommonResult<BigInteger> submitOrders(@Valid @RequestBody OrderCreateReqDTO reqDTO) {
        Long userId = getLoginUserId();
        OrderDO orderDO = orderService.getOrderByOrderId(reqDTO.getOrderId());

        log.info("[OrderController][submitOrders][userid][orderId]={},{}",userId,reqDTO.getOrderId());
        log.info("[OrderController][submitOrders][orderDO]={}",orderDO);
        // 看看订单有没有过期
        if (orderDO == null || orderDO.getOrderStatus() == -4) {
            return CommonResult.error(ErrorCodeConstants.ORDER_EXPIRED);
        }
        // 重算一遍订单金额
        OrderAmtDTO orderAmtDTO = recalculateAmountWhenFinishingCalculateShop(reqDTO.getSpuId(), reqDTO.getSkuId(), reqDTO.getAllCount());
        log.info("[OrderController][submitOrders][orderAmtDTO]{}",orderAmtDTO);
        Object orderCache = redisTemplate.opsForValue().get(OrderCacheNames.ORDER_CONFIRM_KEY + reqDTO + CacheNames.UNION_KEY + reqDTO.getAllCount());
        if (orderCache != null) {
            throw exception(ORDER_SUBMIT_DUPLICATE);
        }
        //订单金额不能超过50000元
        if (orderAmtDTO.getTotal().compareTo(new BigDecimal(50000)) == 1) {
            return CommonResult.error(ErrorCodeConstants.ORDER_AMT_MAX_EXISTS);
        }
        // 缓存，防止重复提交
        redisTemplate.opsForValue().set(OrderCacheNames.ORDER_CONFIRM_KEY + reqDTO + CacheNames.UNION_KEY + reqDTO.getAllCount(), userId, 30L, TimeUnit.MINUTES);
        reqDTO.setTotal(orderAmtDTO.getTotal());
        reqDTO.setUserId(BigInteger.valueOf(getLoginUserId()));
        reqDTO.setPic(orderAmtDTO.getPic());
        reqDTO.setProductPrice(orderAmtDTO.getProductPrice());
        BigInteger orderId = orderService.submitOrder(reqDTO);
        return success(orderId);
    }

    /**
     * 这里有提交订单的代码（单个sku）
     * 提交订单,
     */
    @PostMapping("/toPay")
    @Operation(summary = "提交订单，返回支付流水号", description = "根据传入的参数判断是否为购物车提交订单，同时对购物车进行删除，用户开始进行支付")
    public CommonResult<Object> toPay(@Valid @RequestBody OrderToPayReqDTO reqDTO, HttpServletRequest request) {
        OrderDO orderDO = orderService.get(reqDTO.getOrderId());
        if(orderDO==null){
            return CommonResult.error(ErrorCodeConstants.ORDER_NOT_EXISTS);
        }
        // 查询店铺信息
        ShopDetailRespDTO shopDetail = shopDetailApi.getShopDetail(orderDO.getShopId()).getCheckedData();

        PayOrderCreateReqDTO payDTO= new PayOrderCreateReqDTO();
        payDTO.setAppId(appId);
        payDTO.setAppUserId(shopDetail.getAppUserId());
        String no = PayOrderNo.ORDER_NO_PREFIX + IdUtil.getSnowflakeNextId();
        payDTO.setMerchantOrderId(no);
        payDTO.setUserIp(ServletUtils.getClientIP());
        payDTO.setSubject(orderDO.getSpuName());
        payDTO.setBody(orderDO.getShopName()+orderDO.getSpuName());
        BigDecimal amount=orderDO.getTotal().multiply(new BigDecimal(100));
        payDTO.setAmount(amount.intValue());//
        payDTO.setExpireTime(LocalDateTimeUtil.offset(LocalDateTime.now(), 30, ChronoUnit.MINUTES));
        payDTO.setOrderType(7);  // 5:分账(分账必填,否则走直销) 7:分账(内部订单)
        log.info("[OrderController][toPay][payDTO]=={},",payDTO);
        CommonResult<BigInteger> resultData = payOrderApi.createOrder(payDTO);
        log.info("[OrderController][toPay][resultData]=={},",resultData);
        BigInteger resultId = resultData.getData();
        if(resultId == null){
            return CommonResult.error(ErrorCodeConstants.ORDER_TO_PAY_ERROR);
        }

        log.info("[OrderController][toPay][resultId]=={}",resultId);
        OrderDO updateReqVO=  new OrderDO();
        updateReqVO.setId(orderDO.getId());
        updateReqVO.setOutTradeNo(resultId.toString());
        updateReqVO.setMerchantOrderId(no);
        log.info("[OrderController][toPay][updateReqVO]=={}",updateReqVO);
        orderService.updateOrderNo(updateReqVO);
        return success(resultId);
    }

    /**
     * 发货
     */
    @PutMapping("/delivery")
    @Operation(summary = "根据订单号发货", description = "根据订单号发货")
    public CommonResult<Object> delivery(@Valid @RequestBody OrderDeliveryReqDTO orderParam) {
        log.info("[delivery][orderParam]=={}",orderParam);
        OrderDO order = orderService.getOrderByOrderId(orderParam.getOrderId());
        log.info("[delivery][order]=={}",order);
        if (order==null) {
            // 订单未支付发货，无法确认收货
            return CommonResult.error(ErrorCodeConstants.ORDER_NOT_EXISTS);
        }
        if (order.getOrderStatus()!=OrderStatusEnum.PAYED.value()) {
            // 订单未支付发货，无法确认收货
            return CommonResult.error(ErrorCodeConstants.ORDER_NOT_PAYED);
        }
        // 发货
        OrderDO orderDO = new OrderDO();
        orderDO.setId(orderParam.getOrderId());
        orderDO.setOrderStatus(OrderStatusEnum.CONSIGNMENT.value());
        orderDO.setDeliveryTime(LocalDateTime.now());
        orderDO.setDeliveryFile(orderParam.getDeliveryFile());
        orderService.updateOrderStatus(orderDO);

        // 发送mq消息
        orderDeliverForHzhProducer.sendOrderDeliverMessage(order, getLoginUserId());
        return success(orderDO.getId());
    }

    /**
     * 卖家家订单列表-分页获取
     */
    @GetMapping("/search_order")
    @Operation(summary = "订单列表信息查询", description = "根据订单编号或者订单中商品名称搜索")
    public CommonResult<PageResult<OrderRespVO>> searchOrder(@Valid OrderPageReqVO pageVO) {
        PageResult<OrderRespVO> pageResult = orderService.getMiniPage(pageVO);
        return success(pageResult);
    }

    /**
     * 卖家家订单汇总
     */
    @GetMapping("/shop_order")
    @Operation(summary = "卖家家订单汇总", description = "卖家家订单汇总")
    public CommonResult<OrderShopRespVO> getShopOrder(@RequestParam(value = "shopId") BigInteger shopId) {
        OrderShopRespVO orderShopRespVO= new OrderShopRespVO();
        log.info("[OrderController][getShopOrder][shopId]=,{}",shopId);
        orderShopRespVO.setTotalNumber(orderService.getCountByStatus(4,shopId).intValue());
        orderShopRespVO.setUnshippedNumber(orderService.getCountByStatus(OrderStatusEnum.PAYED.value(),shopId).intValue());
        orderShopRespVO.setUnreceivedGoodsNumber(orderService.getCountByStatus(OrderStatusEnum.CONSIGNMENT.value(),shopId).intValue());
        orderShopRespVO.setFinallyNumber(orderService.getCountByStatus(OrderStatusEnum.SUCCESS.value(),shopId).intValue());
        return success(orderShopRespVO);

    }

    /**
     * 商家信息待发货数据
     */
    @GetMapping("/shop_unshipped_number")
    @Operation(summary = "商家信息待发货数据", description = "商家信息待发货数据")
    public CommonResult<Object> getUnshippedNumber(@RequestParam(value = "shopId") BigInteger shopId) {
        log.info("[OrderController][getUnshippedNumber][shopId]=,{}",shopId);
        int  unshippedNumber=orderService.getCountByStatus(OrderStatusEnum.PAYED.value(),shopId).intValue();
        return success(unshippedNumber);
    }

    /**
     * 重算一遍订单金额,返回总金额
     */
    private OrderAmtDTO recalculateAmountWhenFinishingCalculateShop(BigInteger spuId, BigInteger skuId, Integer allCount) {
        log.info("[OrderController][recalculateAmountWhenFinishingCalculateShop],spuId=={},skuId=={}",spuId,skuId);
        // 重算一遍订单金额
        BigDecimal productPrice = BigDecimal.ZERO;
        SpuDTO spuDTO=spuApi.getSpu(spuId).getData();
        productPrice = spuDTO.getPriceFee();
        if (!Objects.equals(skuId,spuId)) {//判断不等于，需要查询sku价格
            log.info("spuId=={},skuId=={}",spuId,skuId);
            productPrice = skuApi.getSku(skuId).getData().getPriceFee();
            log.info("[OrderController][skuApi],productPrice=={}",productPrice);
        }
        log.info("[OrderController][recalculateAmountWhenFinishingCalculateShop],productPrice=={}",productPrice);
        return OrderAmtDTO.builder().total(productPrice.multiply(new BigDecimal(allCount))).productPrice(productPrice).pic(spuDTO.getMainImgUrl()).build();
    }


}
